package com.lxh.iot.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;

import com.lxh.common.core.utils.DateUtils;
import com.lxh.common.redis.service.RedisService;
import com.lxh.common.security.utils.SecurityUtils;
import com.lxh.iot.domain.Product;
import com.lxh.iot.domain.ThingsModel;
import com.lxh.iot.domain.ThingsModelTemplate;
import com.lxh.iot.mapper.ProductMapper;
import com.lxh.iot.mapper.ThingsModelMapper;
import com.lxh.iot.mapper.ThingsModelTemplateMapper;
import com.lxh.iot.model.ImportThingsModelInput;
import com.lxh.iot.model.ThingsModelItem.DataType;
import com.lxh.iot.model.ThingsModels.*;
import com.lxh.iot.service.IThingsModelService;
import com.lxh.system.api.domain.SysUser;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

/**
 * 物模型Service业务层处理
 *
 *
 * @date 2021-12-16
 */
@Service
public class ThingsModelServiceImpl implements IThingsModelService
{
    private String tslPreKey ="TSL:";

    @Autowired
    private ThingsModelMapper thingsModelMapper;

    @Autowired
    private ThingsModelTemplateMapper thingsModelTemplateMapper;

    @Autowired
    private ProductMapper productMapper;

    @Autowired
    private RedisService redisService;

    /**
     * 查询物模型
     *
     * @param modelId 物模型主键
     * @return 物模型
     */
    @Override
    public ThingsModel selectThingsModelByModelId(Long modelId)
    {
        return thingsModelMapper.selectThingsModelByModelId(modelId);
    }

    /**
     * 查询物模型列表
     *
     * @param thingsModel 物模型
     * @return 物模型
     */
    @Override
    public List<ThingsModel> selectThingsModelList(ThingsModel thingsModel)
    {
        return thingsModelMapper.selectThingsModelList(thingsModel);
    }

    /**
     * 新增物模型
     *
     * @param thingsModel 物模型
     * @return 结果
     */
    @Override
    public int insertThingsModel(ThingsModel thingsModel)
    {
        // 物模型标识符不能重复 TODO 重复查询待优化
        ThingsModel input=new ThingsModel();
        input.setProductId(thingsModel.getProductId());
        List<ThingsModel> list=thingsModelMapper.selectThingsModelList(input);
        Boolean isRepeat=list.stream().anyMatch(x->x.getIdentifier().equals(thingsModel.getIdentifier()));
        if(!isRepeat) {
            SysUser user = SecurityUtils.getLoginUser().getSysUser();
            thingsModel.setTenantId(user.getUserId());
            thingsModel.setTenantName(user.getUserName());
            thingsModel.setCreateTime(DateUtils.getNowDate());
            int result = thingsModelMapper.insertThingsModel(thingsModel);
            // 更新redis缓存
            setCacheThingsModelByProductId(thingsModel.getProductId());
            return result;
        }
        return 2;
    }

    /**
     * 导入通用物模型
     * @param input
     * @return
     */
    @Override
    public int importByTemplateIds(ImportThingsModelInput input){
        // 物模型标识符不能重复 TODO 重复查询待优化
        ThingsModel inputParameter=new ThingsModel();
        inputParameter.setProductId(input.getProductId());
        List<ThingsModel> dbList=thingsModelMapper.selectThingsModelList(inputParameter);

        SysUser user = SecurityUtils.getLoginUser().getSysUser();
        // 根据ID集合获取通用物模型列表
        List<ThingsModelTemplate> templateList=thingsModelTemplateMapper.selectThingsModelTemplateByTemplateIds(input.getTemplateIds());
        //转换为产品物模型，并批量插入
        List<ThingsModel> list=new ArrayList<>();
        int repeatCount=0;
        for(ThingsModelTemplate template : templateList){
            ThingsModel thingsModel= new ThingsModel();
            BeanUtils.copyProperties(template,thingsModel);
            thingsModel.setTenantId(user.getUserId());
            thingsModel.setTenantName(user.getUserName());
            thingsModel.setCreateTime(DateUtils.getNowDate());
            thingsModel.setProductId(input.getProductId());
            thingsModel.setProductName(input.getProductName());
            thingsModel.setModelId(template.getTemplateId());
            thingsModel.setModelName(template.getTemplateName());
            thingsModel.setIsReadonly(template.getIsReadonly());
            thingsModel.setModelOrder(template.getModelOrder());
            thingsModel.setModelIcon(template.getModelIcon());
            Boolean isRepeat=dbList.stream().anyMatch(x->x.getIdentifier().equals(thingsModel.getIdentifier()));
            if(isRepeat){
                repeatCount=repeatCount+1;
            }else{
                list.add(thingsModel);
            }
        }
        if(list.size()>0) {
            thingsModelMapper.insertBatchThingsModel(list);
            //更新redis缓存
            setCacheThingsModelByProductId(input.getProductId());
        }
        return repeatCount;
    }

    /**
     * 修改物模型
     *
     * @param thingsModel 物模型
     * @return 结果
     */
    @Override
    public int updateThingsModel(ThingsModel thingsModel)
    {
        // 物模型标识符不能重复 TODO 重复查询待优化
        ThingsModel input=new ThingsModel();
        input.setProductId(thingsModel.getProductId());
        List<ThingsModel> list=thingsModelMapper.selectThingsModelList(input);
        Boolean isRepeat=list.stream().anyMatch(x->x.getIdentifier().equals(thingsModel.getIdentifier()) && x.getModelId().longValue()!=thingsModel.getModelId());
        if(!isRepeat) {
            thingsModel.setUpdateTime(DateUtils.getNowDate());
            int result = thingsModelMapper.updateThingsModel(thingsModel);
            // 更新redis缓存
            setCacheThingsModelByProductId(thingsModel.getProductId());
            return result;
        }
        return 2;
    }

    /**
     * 批量删除物模型
     *
     * @param modelIds 需要删除的物模型主键
     * @return 结果
     */
    @Override
    public int deleteThingsModelByModelIds(Long[] modelIds)
    {
        ThingsModel thingsModel=thingsModelMapper.selectThingsModelByModelId(modelIds[0]);
        int result=thingsModelMapper.deleteThingsModelByModelIds(modelIds);
        // 更新redis缓存
        setCacheThingsModelByProductId(thingsModel.getProductId());

        return result;
    }

    /**
     * 删除物模型信息
     *
     * @param modelId 物模型主键
     * @return 结果
     */
    @Override
    public int deleteThingsModelByModelId(Long modelId)
    {
        ThingsModel thingsModel=thingsModelMapper.selectThingsModelByModelId(modelId);
        int result=thingsModelMapper.deleteThingsModelByModelId(modelId);
        // 更新redis缓存
        setCacheThingsModelByProductId(thingsModel.getProductId());
        return result;
    }

    /**
     * 根据产品ID获取JSON物模型
     * @param productId
     * @return
     */
    @Override
    public String getCacheThingsModelByProductId(Long productId){
        // redis获取物模型
        String thingsModelJson = redisService.getCacheObject(tslPreKey +productId);
        if (thingsModelJson != null){
            return thingsModelJson;
        }
        return setCacheThingsModelByProductId(productId);
    }

    /**
     * 根据产品缓存的物模型，将对象，简单数组和对象数组都拆开成单个物模型
     * @param productId
     * @return
     */
    @Override
    public String getCacheThingsModelToSingleThingsModelByProductId(Long productId){
        String cacheThingsModel = getCacheThingsModelByProductId(productId);
        JSONObject thingsModelObject = JSONObject.parseObject(cacheThingsModel);
        JSONArray properties = thingsModelObject.getJSONArray("properties");
        JSONArray functions = thingsModelObject.getJSONArray("functions");
        JSONArray events = thingsModelObject.getJSONArray("events");
        Map<String,List<com.lxh.iot.model.ThingsModelItem.ThingsModel>> thingsModesMap = new HashMap<>();
        thingsModesMap.put("properties",convertThingsModelToSingleModel(properties));
        thingsModesMap.put("functions",convertThingsModelToSingleModel(functions));
        thingsModesMap.put("events",convertThingsModelToSingleModel(events));
        //避免出现$ref
        return JSON.toJSONString(thingsModesMap, SerializerFeature.DisableCircularReferenceDetect);
    }

    /**
     * 将thingsModels的对象 简单数组 对象数组转换成单个物模型
     * @param thingsModelsArray
     * @return
     */
    public List<com.lxh.iot.model.ThingsModelItem.ThingsModel> convertThingsModelToSingleModel(JSONArray thingsModelsArray){
        List<com.lxh.iot.model.ThingsModelItem.ThingsModel> thingsModels = thingsModelsArray.toJavaList(com.lxh.iot.model.ThingsModelItem.ThingsModel.class);
        List<com.lxh.iot.model.ThingsModelItem.ThingsModel> thingsModelList = new ArrayList<>();
        for(int n =0;n<thingsModels.size();n++){
            com.lxh.iot.model.ThingsModelItem.ThingsModel thingsModel = thingsModels.get(n);
            DataType dataType = thingsModels.get(n).getDataType();
            if (dataType == null) {
                continue;
            }
            //对象
            if (dataType.getType().equals("object")) {
                List<com.lxh.iot.model.ThingsModelItem.ThingsModel> params = dataType.getParams();
                if (params == null) {
                    continue;
                }
                params.forEach(p -> {
                    p.setName(thingsModel.getName()+"-"+p.getName());
                    thingsModelList.add(p);
                });
            }
            //数组
            else if (dataType.getType().equals("array") && !dataType.getArrayType().equals("object")) {
                Integer arrayCount = dataType.getArrayCount();
                if(arrayCount==null){
                    continue;
                }
                for(int i=0;i<arrayCount;i++){
                    com.lxh.iot.model.ThingsModelItem.ThingsModel tm = new com.lxh.iot.model.ThingsModelItem.ThingsModel();
                    BeanUtils.copyProperties(thingsModel,tm);
                    tm.setName(tm.getName()+"["+Integer.toString(i+1)+"]");
                    tm.setId("array_"+String.format("%02d", i)+"_"+tm.getId());
                    tm.getDataType().setType(thingsModel.getDataType().getArrayType());
                    thingsModelList.add(tm);
                }
            }
            //对象数组
            else if (dataType.getType().equals("array") && dataType.getArrayType().equals("object")) {
                Integer arrayCount = dataType.getArrayCount();
                List<com.lxh.iot.model.ThingsModelItem.ThingsModel> params = dataType.getParams();
                if(arrayCount==null || params==null){
                    continue;
                }
                for (int i = 0; i < arrayCount; i++) {
                    for (int j = 0; j < params.size(); j++) {
                        com.lxh.iot.model.ThingsModelItem.ThingsModel tm = new com.lxh.iot.model.ThingsModelItem.ThingsModel();
                        BeanUtils.copyProperties(params.get(j),tm);
                        tm.setName(thingsModel.getName()+"["+Integer.toString(i+1)+"]"+"-"+tm.getName());
                        tm.setId("array_"+String.format("%02d", i)+"_"+tm.getId());
                        thingsModelList.add(tm);
                    }
                }
            }
            //普通
            else {
                thingsModelList.add(thingsModels.get(n));
            }
        }
        return thingsModelList;
    }

    /**
     * 根据产品ID更新JSON物模型
     * @param productId
     * @return
     */
    private String setCacheThingsModelByProductId(Long productId){
        // 数据库查询物模型集合
        ThingsModel model=new ThingsModel();
        model.setProductId(productId);
        List<ThingsModel> thingsModels=thingsModelMapper.selectThingsModelList(model);
        // 转换为物模型
        ThingsModelsDto thingsModelsDto=new ThingsModelsDto();
        for(int i=0;i<thingsModels.size();i++){
            if(thingsModels.get(i).getType()==1){
                // 属性
                PropertyDto propertyDto=new PropertyDto();
                propertyDto.setId(thingsModels.get(i).getIdentifier());
                propertyDto.setName(thingsModels.get(i).getModelName());
                propertyDto.setIsMonitor(thingsModels.get(i).getIsMonitor());
                propertyDto.setIsTop(thingsModels.get(i).getIsTop());
                propertyDto.setIsReadonly(thingsModels.get(i).getIsReadonly());
                propertyDto.setIsRecord(thingsModels.get(i).getIsRecord());
                propertyDto.setOrder(thingsModels.get(i).getModelOrder());
                propertyDto.setModelIcon(thingsModels.get(i).getModelIcon());
                propertyDto.setDatatype(JSONObject.parseObject(thingsModels.get(i).getSpecs()));
                thingsModelsDto.getProperties().add(propertyDto);
            }else if(thingsModels.get(i).getType()==2){
                // 功能
                FunctionDto functionDto=new FunctionDto();
                functionDto.setId(thingsModels.get(i).getIdentifier());
                functionDto.setName(thingsModels.get(i).getModelName());
                functionDto.setIsTop(thingsModels.get(i).getIsTop());
                functionDto.setIsReadonly(thingsModels.get(i).getIsReadonly());
                functionDto.setIsMonitor(thingsModels.get(i).getIsMonitor());
                functionDto.setIsRecord(thingsModels.get(i).getIsRecord());
                functionDto.setOrder(thingsModels.get(i).getModelOrder());
                functionDto.setModelIcon(thingsModels.get(i).getModelIcon());
                functionDto.setDatatype(JSONObject.parseObject(thingsModels.get(i).getSpecs()));
                thingsModelsDto.getFunctions().add(functionDto);
            }else if(thingsModels.get(i).getType()==3){
                // 事件
                EventDto eventDto=new EventDto();
                eventDto.setId(thingsModels.get(i).getIdentifier());
                eventDto.setName(thingsModels.get(i).getModelName());
                eventDto.setIsTop(thingsModels.get(i).getIsTop());
                eventDto.setIsReadonly(thingsModels.get(i).getIsReadonly());
                eventDto.setIsMonitor(thingsModels.get(i).getIsMonitor());
                eventDto.setIsRecord(thingsModels.get(i).getIsRecord());
                eventDto.setDatatype(JSONObject.parseObject(thingsModels.get(i).getSpecs()));
                eventDto.setModelIcon(thingsModels.get(i).getModelIcon());
                thingsModelsDto.getEvents().add(eventDto);
            }
        }
        JSONObject tslObject= (JSONObject) JSONObject.toJSON(thingsModelsDto);
        redisService.setCacheObject(tslPreKey +productId,tslObject.toJSONString());
        Product product=new Product();
        product.setProductId(productId);
        product.setThingsModelsJson(tslObject.toJSONString());
        productMapper.updateThingsModelJson(product);
        return tslObject.toJSONString();
    }

    /**
     * 批量查询产品的缓存物模型
     * @param productIds
     * @return
     */
    @Override
    public Map<String, String> getBatchCacheThingsModelByProductIds(Long[] productIds){
        // 批量查询hkey和value
        Set<String> set=new HashSet<>();
        for(int i=0;i<productIds.length;i++){
            set.add(tslPreKey+productIds[i]);
        }
        Map<String, String> map=redisService.getStringAllByKeys(set);
        // 如果redis键和设备不匹配，添加redis缓存
        if(map==null || map.size()!=productIds.length){
            for(int i=0;i<productIds.length;i++){
                String key=tslPreKey+productIds[i];
                if(map.get(key)!=null){
                    continue;
                }else{
                    map.put(key,setCacheThingsModelByProductId(productIds[i]));
                }
            }
        }
        return map;
    }
    /**
     * 根据产品ID查询产品缓存中的物模型
     * @param productId
     * @return List<ThingsModel>
     */
    @Override
    public List<com.lxh.iot.model.ThingsModelItem.ThingsModel> getCacheThingsModelsToListByProductId(Long productId) {
        String cacheThingsModel = getCacheThingsModelByProductId(productId);
        JSONObject thingsModelObject = JSONObject.parseObject(cacheThingsModel);
        JSONArray properties = thingsModelObject.getJSONArray("properties");
        JSONArray functions = thingsModelObject.getJSONArray("functions");
        JSONArray mergedJsonArray = new JSONArray(); // 重新创建一个新的JSONArray来存储合并后的结果
        mergedJsonArray.addAll(properties);
        mergedJsonArray.addAll(functions);
        List<com.lxh.iot.model.ThingsModelItem.ThingsModel> thingsModels = mergedJsonArray.toJavaList(com.lxh.iot.model.ThingsModelItem.ThingsModel.class);
        return thingsModels;
    }

    /**
     * 根据产品id和物模型输入的id查询当前的物模型
     * @param productId
     * @param id 设备输入的id
     * @return ThingsModel
     */
    @Override
    public com.lxh.iot.model.ThingsModelItem.ThingsModel getThingsModelByProductIdAndId(Long productId, String id) {
        //id   fatherId_childId  array_01_id   array_01_fatherId_chindId
        String[] s = id.split("_");
        List<com.lxh.iot.model.ThingsModelItem.ThingsModel> thingsModels = getCacheThingsModelsToListByProductId(productId);
        //转成map避免循环
        Map<String, com.lxh.iot.model.ThingsModelItem.ThingsModel> thingsModelMaps = new HashMap<>();
        thingsModels.forEach(t->{
            thingsModelMaps.put(t.getId(),t);
        });
        com.lxh.iot.model.ThingsModelItem.ThingsModel thingsModel = null;
        if(s.length==4){
            String fatherId = s[2];
            String childId = s[2]+"_"+s[3];
            com.lxh.iot.model.ThingsModelItem.ThingsModel tm = thingsModelMaps.get(fatherId);
            if(tm==null){
                thingsModel=null;
            }
            List<com.lxh.iot.model.ThingsModelItem.ThingsModel> params = tm.getDataType().getParams();
            for(com.lxh.iot.model.ThingsModelItem.ThingsModel param : params){
                if(param.getId().equals(childId)){
                    thingsModel=param;
                }
            }
        }else if(s.length==3){
            String childId = s[2];
            thingsModel = thingsModelMaps.get(childId);

        }else if(s.length==2){
            String fatherId = s[0];
            String childId = id;
            com.lxh.iot.model.ThingsModelItem.ThingsModel tm = thingsModelMaps.get(fatherId);
            if(tm==null){
                thingsModel=null;
            }
            List<com.lxh.iot.model.ThingsModelItem.ThingsModel> params = tm.getDataType().getParams();
            for(com.lxh.iot.model.ThingsModelItem.ThingsModel param : params){
                if(param.getId().equals(childId)){
                    thingsModel=param;
                }
            }
        }else if(s.length==1){
            thingsModel = thingsModelMaps.get(id);
        }
        return thingsModel;
    }
    /**
     * 根据步长和上报的值进行转换
     * @param productId
     * @param thingsModelSimpleItem
     * @return
     */
    public String transByStep(Long productId, ThingsModelSimpleItem thingsModelSimpleItem){
        // 根据属性上报的值和触发器里面的值根据操作符来返回结果
        com.lxh.iot.model.ThingsModelItem.ThingsModel thingsModel = getThingsModelByProductIdAndId(productId, thingsModelSimpleItem.getId());
        if(thingsModel==null){
            return "";
        }
        BigDecimal step = thingsModel.getDataType().getStep();
        String value = thingsModelSimpleItem.getValue();
        //integer和decimal进行步长转换，string enum不转换
        if("decimal".equals(thingsModel.getDataType().getType()) || "integer".equals(thingsModel.getDataType().getType())) {
            if (step.compareTo(BigDecimal.ZERO) == 0 || step == null) {
                //如果未设置步长，就按照1来处理
                step = new BigDecimal(1);
            }
            //转换步长之后的值
            String transValue = new BigDecimal(value).divide(step, 1, RoundingMode.HALF_UP).toString();
            return transValue;
        }
        return value;
    }
}
